using UnityEngine;
using System.Collections;
using System.Collections.Generic;

// The maze class
public class Maze : MonoBehaviour {

	// The size of the maze, it's x by y cells big.
	public IntVector2 size;
	// A cell in the maze.
	public MazeCell cell;
	// All of the cells in the maze.
	public MazeCell[,] cells;
	// Wait this long before moving on in generation
	public float generationStepDelay;
	// This is the maze passage prefab
	public MazePassage passagePrefab;
	// This is a wall
	public MazeWall wallPrefab;
	// Check if the maze is finished generating
	public bool doneGenerating = false;
	// Keep track of the player and enemy's scores
	private int enemyScore = 0;
	private int playerScore = 0;
	// This is just for GUI stuff
	private GUIStyle style;

	// Use this for initialization
	void Start () {
		style = new GUIStyle ();
		style.fontSize += 25;
	}

	// Generate the GUI
	void OnGUI () {
		if (doneGenerating) {
			string player = "Player:  " + playerScore; 
			GUI.Label (new Rect (250, 110, 150, 50), player, style);
			string enemy = "Enemy: " + enemyScore; 
			GUI.Label (new Rect (250, 135, 150, 50), enemy, style);
		}
	}

	// Return the cell at the given coordinate.
	public MazeCell GetCell(IntVector2 coordinates) {
		return cells[coordinates.x, coordinates.y];
	}

	// Generate the maze
	public IEnumerator Generate() {
		WaitForSeconds delay = new WaitForSeconds(generationStepDelay);
		cells = new MazeCell[size.x, size.y];
		List<MazeCell> activeCells = new List<MazeCell>();
		DoFirstGenerationStep(activeCells);
		while(activeCells.Count > 0) {
			yield return delay;
			DoNextGenerationStep(activeCells);
		}
		doneGenerating = true;
	}

	// Create a cell at the given coordinates
	private MazeCell CreateCell(IntVector2 coordinates) {
		MazeCell newCell = Instantiate(cell) as MazeCell;
		cells[coordinates.x, coordinates.y] = newCell;
		newCell.coordinates = coordinates;
		newCell.name = "Maze Cell " +  coordinates.x + ", " + coordinates.y;
		newCell.transform.parent = transform;
		newCell.transform.localPosition = new Vector3(coordinates.x - size.x * 0.5f + 0.5f, coordinates.y - size.y * 0.5f + 0.5f, 0f);
		return newCell;
	}

	// Start at a random coordinate and create a cell there.
	private void DoFirstGenerationStep (List<MazeCell> activeCells) {
		activeCells.Add(CreateCell (RandomCoordinates));
	}

	// Follow it up by building from that cell.
	private void DoNextGenerationStep(List<MazeCell> activeCells) {
		int currentIndex = activeCells.Count - 1;
		MazeCell currentCell = activeCells[currentIndex];
		if(currentCell.IsFullyInitialized) {
			activeCells.RemoveAt(currentIndex);
			return;
		}
		MazeDirection direction = currentCell.RandomUninitializedDirection;
		IntVector2 coordinates = currentCell.coordinates + direction.ToIntVector2();
		if (ContainsCoordinates (coordinates)) {
			MazeCell neighbor = GetCell (coordinates);
			if (neighbor == null) {
				neighbor = CreateCell (coordinates);
				CreatePassage (currentCell, neighbor, direction);
				activeCells.Add (neighbor);
			} else {
				CreateWall (currentCell, neighbor, direction);
			}
		}
		else {
				CreateWall(currentCell, null, direction);
		}
	}

	// Return random coordinates
	public IntVector2 RandomCoordinates {
		get {
			return new IntVector2(Random.Range(0, size.x), Random.Range(0, size.y));
		}
	}

	// Does the maze contain the given coordinates already?
	public bool ContainsCoordinates(IntVector2 coordinate) {
		return coordinate.x >= 0 && coordinate.x < size.x && coordinate.y >= 0 && coordinate.y < size.y;
	}

	// Create a passage between two cells
	private void CreatePassage (MazeCell cell, MazeCell otherCell, MazeDirection direction) {
		MazePassage passage = Instantiate (passagePrefab) as MazePassage;
		passage.Initialize (cell, otherCell, direction);
		passage = Instantiate (passagePrefab) as MazePassage;
		passage.Initialize (otherCell, cell, direction.GetOpposite ());
	}

	// Create a wall between two cells.
	private void CreateWall (MazeCell cell, MazeCell otherCell, MazeDirection direction) {
		MazeWall wall = Instantiate (wallPrefab) as MazeWall;
		wall.Initialize (cell, otherCell, direction);
		if(otherCell != null) {
			wall = Instantiate(wallPrefab) as MazeWall;
			wall.Initialize(otherCell, cell, direction.GetOpposite());
		}
	}

	// Get the space for the grid.
	public IntVector2 getGridSpace(Vector3 pos) {
		return new IntVector2(0,0);
	}

	// Update the player score by the given parameter
	public void playerCount(int num) {
		playerScore += num;
	}

	// Update the enemy score by the given parameter
	public void enemyCount(int num) {
		enemyScore += num;
	}

	// Return the player's score
	public int getPlayerScore() {
		return playerScore;
	}

	// Return the enemy's score
	public int getEnemyScore() {
		return enemyScore;
	}
}
